﻿unit TCPListener;
{$I IOCP.inc}

interface

uses
  Winapi.Windows, System.SysUtils, WinSock2Ex, Engine, MemBuffer, WinSocket,
  Protocol, CriticalSection, ContextFactory, MemoryPool,
  IThread, IOCompletionPort;

type
  TITcpListener = class;
  (* IP安全验证事件       *)
  TOnSecurityIPEvent = function(sIPAddress: AnsiString): Boolean of object;
  (* 创建上下文事件       *)
  TOnCreateClientEvent = function: TIClientContext of object;
  (* TCP侦听引擎线程      *)
  TDIListenerThread = class(TIThread)
  private
    _TCPListener: TITCPListener;
  protected
    procedure ThreadRoutine; override;
  public
    constructor Create(FDITcpListener: TITcpListener);
    destructor Destroy; override;
  end;

  (* TCP侦听引擎          *)
  TITcpListener = class
  private
    m_nPort:                    Integer;              (* 端口号                 *)
    m_bStarted:                 Boolean;              (* 是否启动               *)
    m_sListenSocket:            TSocket;              (* 侦听Socket套接字       *)
    m_bNagle:                   Boolean;              (* Nagle算法              *)
    m_bKeepAlive:               Boolean;              (* KeepAlive保活          *)
    m_nKeepAliveTime:           Integer;              (* KeepAlive保活时间(秒)  *)
    m_bReuseAddr:               Boolean;              (* 端口重用               *)
    m_iMaxNumConnections:       Cardinal;                (* 允许最多客户端连接个数 *)
    m_nInitPostAcceptEx:        Cardinal;                (* 初次投递AcceptEx个数   *)
    m_nMaxPostAcceptEx:         Cardinal;                (* AcceptEx池中最大个数   *)
    m_iIOCPPostAccepts:         Integer;              (* 需要投递AcceptEx个数   *)

    m_hPostAcceptEvent:         Thandle;              (* Accept I/O事件内核对象 *)
    m_hListnerThreadEvent:      Thandle;              (* WSAEventSelectI/O 事件 *)
    m_hShutdownEvent:           Thandle;              (* 停止服务事件           *)
    m_hListnerEngineThread:     TDIListenerThread;    (* 侦听线程               *)
    m_hWaitEventList:           array of Thandle;     (* Wait线程内核对象列表   *)
    m_DIEngine:                 TIEngine;            (* Socket引擎             *)
    m_OnSecurityIPEvent:        TOnSecurityIPEvent;   (* 安全连接判断事件       *)
    m_lpfnAcceptEx:             LPFN_ACCEPTEX;        (* AcceptEx函数地址       *)
    m_lpfnGetAcceptExSockaddr:  LPFN_GetAcceptExSocketaddr;(*GetAcceptSockaddrs *)
    m_mapClientContext:         TIMapClientContext;  (* Socket上下文管理       *)
    m_OnCreateClientEvent:      TOnCreateClientEvent; (* 创建上下文事件         *)
    function GetNumberOfActiveConnections: Cardinal;           (*在线Socket连接数  *)
  published
    property FPort: Integer read m_nPort write m_nPort;
    property FNagle: Boolean read m_bNagle write m_bNagle;
    property FKeepAlive: Boolean read m_bKeepAlive write m_bKeepAlive;
    property FKeepAliveTime: Integer read m_nKeepAliveTime write m_nKeepAliveTime;
    property FReuseAddr: Boolean read m_bReuseAddr write m_bReuseAddr;
    property FInitPostAcceptEx: Cardinal read m_nInitPostAcceptEx;
    property FMaxNumConnections: Cardinal read m_iMaxNumConnections
                                       write m_iMaxNumConnections;
    property FNumberOfActiveConnections: Cardinal read GetNumberOfActiveConnections;
    property FMapClientContext: TIMapClientContext read m_mapClientContext;
    property FOnSecurityIPEvent: TOnSecurityIPEvent read m_OnSecurityIPEvent
                                                    write m_OnSecurityIPEvent;
    property FOnCreateClientEvent: TOnCreateClientEvent read m_OnCreateClientEvent
                                                        write m_OnCreateClientEvent;

  public
    (* 释放所有上下文内存           *)
    procedure FreeClientContexts;

  protected
    (* 侦听线程                     *)
    procedure ListnerThreadProc;

  private
    (* 投递完成端口AcceptEx I/O消息 *)
    function PostWSAAcceptExEvent(FAcceptExBuffer: TIBuffer): Boolean;
    (* 初始化投递AcceptEx I/O数量   *)
    procedure InitPostAcceptEx(nPostAcceptEx: Cardinal);
    (* 处理AcceptEx消息             *)
    procedure OnWSAAcceptEx(FAcceptExBuffer: TIBuffer);
    (* 判断相应的IP地址判断是否合法并且生成上下文并投递Recv I/O操作 *)
    function AssociateIncomingClientWithContext(FAcceptExBuffer: TIBuffer): Boolean;
    (* 关闭所有上下文连接           *)
    procedure CloseAllClientContext;

  public
    (* 完成端口回调AcceptEx         *)
    procedure CallBackAcceptEx(FAcceptExBuffer: TIBuffer);
    (* 启动侦听流程并进行自注册     *)
    function StartListener(FEngine: TIEngine): Boolean;
    (* 停止侦听流程                 *)
    procedure StopListener;

  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses IException, MapBuffer, GlobalLogger;

{ TDIListenerThread }
constructor TDIListenerThread.Create(FDITcpListener: TITcpListener);
begin
  inherited Create;
  _TCPListener := FDITcpListener;
end;

destructor TDIListenerThread.Destroy;
begin
  inherited Destroy;
end;

procedure TDIListenerThread.ThreadRoutine;
begin
  _TCPListener.ListnerThreadProc;
end;

{ TITcpListener }
constructor TITCPListener.Create;
begin
  inherited Create;
  m_nPort := 8988;
  m_bNagle := True;
  m_bKeepAlive := False;
  m_bReuseAddr := False;
  m_bStarted := False;
  m_nKeepAliveTime := 60*5;
  m_iMaxNumConnections := 10000;
  m_nInitPostAcceptEx := 100;
  m_nMaxPostAcceptEx := 500;
  m_sListenSocket := INVALID_SOCKET;
  m_MapClientContext := TIMapClientContext.Create;
end;

destructor TITCPListener.Destroy;
begin
  FreeClientContexts;
  FreeAndNil(m_MapClientContext);
  inherited Destroy;
end;

procedure TITCPListener.CallBackAcceptEx(FAcceptExBuffer: TIBuffer);
begin
  OnWSAAcceptEx(FAcceptExBuffer);
end;

procedure TITCPListener.FreeClientContexts;
{$IFDEF _ICOP_DEBUG}
var
  i: Integer;
  FDIClientContext: TDIClientContext;
{$ENDIF}
begin
  {$IFDEF _ICOP_DEBUG}
  _GlobalLogger.AppendLogMessage(IOCP_DEBUG_MAP_FREECLIENT, [FMapClientContext.FClientContextCount]);
  FMapClientContext.MapClientContextLock.Lock;
  if FMapClientContext.FClientContextCount > 0 then
  for i := 1 to FMapClientContext.FClientContextCount do
  begin
    FDIClientContext := FMapClientContext.FindDIClientContext(I);
    if Assigned(FDIClientContext) then
      _GlobalLogger.AppendLogMessage(IOCP_DEBUG_DISCONNCLIENT,
        [FDIClientContext.FMapID, GUIDToString(FDIClientContext.FGUID)]);
  end;
  FMapClientContext.MapClientContextLock.UnLock;
  {$ENDIF}
  m_MapClientContext.FreeClientContexts;
end;


function TITCPListener.GetNumberOfActiveConnections: Cardinal;
begin
  Result := m_mapClientContext.ActiveClientCount;
end;

procedure TITCPListener.InitPostAcceptEx(nPostAcceptEx: Cardinal);
var
  i: integer;
  pAcceptExBuffer: TIBuffer;
begin
  for i := 1 to nPostAcceptEx do
  begin
    pAcceptExBuffer := m_DIEngine.MemoryPool.AllocateBuffer(IO_WSA_ACCEPTEX);
    if (pAcceptExBuffer = nil) then
      begin
        {$IFDEF _ICOP_DEBUGERR}
        _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_ALLOCATE', []);
        {$ENDIF}
        Exit;
      end
    else
      begin
        if not PostWSAAcceptExEvent(pAcceptExBuffer) then
        begin
          {$IFDEF _ICOP_DEBUGERR}
          _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_POSTWSAACCEPTEX', []);
          {$ENDIF}
        end;
      end;
  end;
end;

function TITCPListener.PostWSAAcceptExEvent(FAcceptExBuffer: TIBuffer): Boolean;
var
  nRetVal: LongBool;
  FAcceptSocket: TSocket;
begin
  Result := False;
  if CreateTCPOverlapSocket(FAcceptSocket) then
  begin
    with FAcceptExBuffer do
    begin
      SetOperation(IO_WSA_ACCEPTEX);
      SetCallBackObj(Self);
      SetupRead;
      FSocket := FAcceptSocket;
      nRetVal := m_lpfnAcceptEx(m_sListenSocket, FSocket, GetBuffer, 0,
        SizeOf(TSockAddrIn) + 16, SizeOf(TSockAddrIn) + 16, 0,
        POverlapped(@OverLappedEx.FOverlapped));
      if((nRetVal = False) and (WinSock2Ex.WSAGetLastError() <> WSA_IO_PENDING)) then
        raise TException.Create('m_lpfnAcceptEx');
      Result := True;
    end;;
  end;
end;

procedure TITCPListener.OnWSAAcceptEx(FAcceptExBuffer: TIBuffer);
begin
  if (FAcceptExBuffer.FSocket = INVALID_SOCKET) then
    CloseWinSocket(FAcceptExBuffer.FSocket)
  else
    begin
      (* 1.设置AcceptEx的Socket为ListenSocket状态  *)
      if ChangeSocketModeAccept(FAcceptExBuffer.FSocket, m_sListenSocket) then
        begin
        (* 2.生成客户端上下文, 判断是否安全连接并且投递Recv I/O操作 *)
          if not AssociateIncomingClientWithContext(FAcceptExBuffer) then
            CloseWinSocket(FAcceptExBuffer.FSocket);
        end
      else
        CloseWinSocket(FAcceptExBuffer.FSocket);
    end;
  (* 回收AcceptEx I/O *)
  m_DIEngine.MemoryPool.ReleaseBuffer(FAcceptExBuffer);
  (* 通知监听线程继续再投递一个Accept请求 *)
  InterlockedIncrement(m_iIOCPPostAccepts);
  SetEvent(m_hPostAcceptEvent);
end;

function TITCPListener.AssociateIncomingClientWithContext(FAcceptExBuffer: TIBuffer): Boolean;
var
  bVal: LongBool;
  sRemoteAddr: AnsiString;
  m_pLocalAddr, m_pRemoteAddr: PSockAddr;
  LocalAddrLen, RemoteAddrLen: Integer;
  FClientContext: TIClientContext;
begin
  Result := True;
  (* 是否超过最大连接数         *)
  if (FNumberOfActiveConnections >= m_iMaxNumConnections) then
  begin
     CloseWinSocket(FAcceptExBuffer.FSocket);
     Result := False;
     Exit;
  end;
  (* 获取客户端IP地址, 及端口号 *)
  m_lpfnGetAcceptExSockaddr(FAcceptExBuffer.GetBuffer, 0,
    SizeOf(TSockAddrIn) + 16, SizeOf(TSockAddrIn) + 16, m_pLocalAddr,
    LocalAddrLen, m_pRemoteAddr, RemoteAddrLen );
  if Assigned(m_pRemoteAddr) then
    sRemoteAddr := GetRemoteIPAddr(TSockAddrIn(m_pRemoteAddr^));
  (* IP是否通过安全认证 *)
  if Assigned(FOnSecurityIPEvent) then
    if not FOnSecurityIPEvent(sRemoteAddr) then Exit;
  (* nagle算法设置                          *)
  if m_bNagle then
  begin
    bVal := True;
    if not SetSocketNagle(FAcceptExBuffer.FSocket, bVal) then
    begin
      CloseWinSocket(FAcceptExBuffer.FSocket);
      Result := False;
      Exit;
    end;
  end;
  (* 设置心跳KeepAlive                      *)
  if m_bKeepAlive then
  begin
    bVal := True;
    if not SetKeepAlive(FAcceptExBuffer.FSocket, bVal, m_nKeepAliveTime * 1000) then
    begin
      CloseWinSocket(FAcceptExBuffer.FSocket);
      Result := False;
      Exit;
    end;
  end;
  (*  从空闲池中分配一个上下文 连接数加1    *)
  FClientContext := m_mapClientContext.AllocateFreeClientContextFromPool;
  if not Assigned(FClientContext) then
  begin
    CloseWinSocket(FAcceptExBuffer.FSocket);
    Result := False;
    Exit;
  end;
  (* 设置Socket 得到客户端IP地址, 分配GUID  *)
  FClientContext.SetSocket(FAcceptExBuffer.FSocket);
  FClientContext.RemoteIP := sRemoteAddr;
  FClientContext.RemotePort := GetRemotePort(TSockAddrIn(m_pRemoteAddr^));
  (* 关联完成端口 (上下文索引)              *)
  with m_DIEngine.IOCompletionPort do
  begin
    if AssociateSocketWithCompletionPort(FClientContext.FSocket, Cardinal(Pointer(FClientContext))) then
      begin
        FClientContext.SocketConnect;
//        (* 性能分析器                   *)
//        {$IFDEF _ICOP_DEBUGERR}
//        _GlobalMonitor.ProcSocketConnCount(FNumberOfActiveConnections);
//        {$ENDIF}
      end
    else
      begin
        (* 安全关闭客户端套接字               *)
        CloseWinSocket(FAcceptExBuffer.FSocket);
        (* 回收上下文                         *)
        m_mapClientContext.RemoveClientContext(FClientContext);
      end;
  end;
end;

procedure TITCPListener.CloseAllClientContext;
var
  i: Integer;
begin
  m_mapClientContext.MapClientContextLock.Lock;
  for i := 1 to FMapClientContext.ClientContextCount do
  begin
    if (m_mapClientContext.Buckets[i].IsUsed) then
      m_mapClientContext.Buckets[i].ClientContext.CloseSocket;
  end;
  m_mapClientContext.MapClientContextLock.UnLock;
end;

function TITCPListener.StartListener(FEngine: TIEngine): Boolean;
var
  nRet: Integer;
begin
  if m_bStarted then
  begin
    Result := False;
    Exit;
  end;
  m_DIEngine := FEngine;
  (* 初始化Map数量                    *)
  m_mapClientContext.OnCreateClientEvent := m_OnCreateClientEvent;
  m_mapClientContext.InitHasTableLength(m_iMaxNumConnections);
  (* 创建Socket套接字                 *)
  if not CreateTcpOverlapSocket(m_sListenSocket) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_CREATESOCKET', [WinSock2Ex.WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* Socket套接字设置重用             *)
  if m_bReuseAddr then
    if not SetSocketReUseAddr(m_sListenSocket) then
    begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_SET_SO_EXCLUSIVEADDRUSE', [WinSock2Ex.WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 加载扩展函数AcceptEx             *)
  if not LoadAcceptEx(m_sListenSocket, m_lpfnAcceptEx) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_LOAD_ACCEPTEX_FUN', [WinSock2Ex.WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 加载扩展函数GetAcceptExSockaddrs *)
  if not LoadAcceptExSockaddrs(m_sListenSocket, m_lpfnGetAcceptExSockaddr) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_LOAD_GETACCEPTEXADDR_FUN', [WinSock2Ex.WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 绑定套接字                       *)
  if not BindSocket(m_sListenSocket, m_nPort) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_BIND', [WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 侦听套接字                       *)
  if not ListenSocket(m_sListenSocket) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('SOCKET_ERROR_LISTEN', [WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 将监听套节字关联到完成端口，注意，这里为它传递的CompletionKey为0 *)
  if not m_DIEngine.IOCompletionPort.AssociateSocketWithCompletionPort(m_sListenSocket, Cardinal(0)) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendLogMessage('IOCP_ERROR_ASSOCIATE_COMPLETIONPORT', []);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (* 设置Wait线程内核对象列表         *)
  SetLength(m_hWaitEventList, 3);
  (* 停止服务内核对象, 加入WaitThread事件列表           *)
  m_hShutdownEvent := CreateEvent(nil, False, False, nil);
  if (m_hShutdownEvent = WSA_INVALID_EVENT) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('EVENT_ERROR_CREATE_SHUTDOWN', [WSAGetLastError()]);
    {$ENDIF}
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  m_hWaitEventList[0] := m_hShutdownEvent;
  (* 投递Accept I/O事件内核对象, 加入WaitThread事件列表 *)
	m_hPostAcceptEvent := CreateEvent(nil, False, False, nil);
  if (m_hPostAcceptEvent = WSA_INVALID_EVENT) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('EVENT_ERROR_CREATE_POSTACCEPT', [WSAGetLastError()]);
    {$ENDIF}
    WSACloseEvent(m_hShutdownEvent);
    CloseWinSocket(m_sListenSocket);
	  Result := False;
    m_bStarted := False;
    Exit;
  end;
	m_hWaitEventList[1] := m_hPostAcceptEvent;
  (* WSAEventSelectI/O模型处理Accept事件, 加入WaitThread事件列表 *)
  m_hListnerThreadEvent := WSACreateEvent;
  if (m_hListnerThreadEvent = WSA_INVALID_EVENT) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('EVENT_ERROR_CREATE_WSACreateEvent', [WSAGetLastError()]);
    {$ENDIF}
    WSACloseEvent(m_hShutdownEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit
  end;
  m_hWaitEventList[2] := m_hListnerThreadEvent;
  (* 注册FD_ACCEPT事件 *)
	(* 如果投递的AcceptEx I/O不够，线程会接收到FD_ACCEPT网络事件，说明应该投递更多的AcceptEx I/O *)
  nRet := WSAEventSelect(m_sListenSocket, m_hListnerThreadEvent, FD_ACCEPT);
  if (nRet = SOCKET_ERROR) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('EVENT_ERROR_REGISTER_EVENT', [WSAGetLastError()]);
    {$ENDIF}
    WSACloseEvent(m_hShutdownEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    WSACloseEvent(m_hListnerThreadEvent);
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  (*  创建侦听线程                    *)
  m_hListnerEngineThread := TDIListenerThread.Create(self);
  if (m_hListnerEngineThread = nil) then
  begin
    {$IFDEF _ICOP_DEBUGERR}
    _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_CREATE', [WSAGetLastError()]);
    {$ENDIF}
    WSACloseEvent(m_hShutdownEvent);
    WSACloseEvent(m_hPostAcceptEvent);
    WSACloseEvent(m_hListnerThreadEvent);
    CloseWinSocket(m_sListenSocket);
    Result := False;
    m_bStarted := False;
    Exit;
  end;
  m_hListnerEngineThread.RunThread;
	Result := True;
  m_bStarted := True;
end;

procedure TITCPListener.ListnerThreadProc;
var
  nRet: Integer;
  nIndex, m_nPostAccepts: Cardinal;
  Events: TWSANetworkEvents;
  function PostAcceptIOCount: Cardinal;
  begin
    Result := m_nPostAccepts;
    with m_DIEngine.MemoryPool.MapAcceptBuffer do begin
      if GetActiveBufferCount + m_nPostAccepts > m_nMaxPostAcceptEx then
        Result := m_nMaxPostAcceptEx - GetActiveBufferCount;
    end;
  end;
begin
  m_nPostAccepts := 0;
  m_iIOCPPostAccepts := 0;
  (* 投递AcceptEX I/O           *)
  InitPostAcceptEx(m_nInitPostAcceptEx);
  m_DIEngine.EngineWorked := True;
  while (True) do
  begin
    (* 等网络事件m_hPostAcceptEvent事件和m_hListnerEngineThreadEvent事件 *)
    nIndex := WSAWaitForMultipleEvents(3, @m_hWaitEventList[0], False, WSA_INFINITE, False);
    if (nIndex = WSA_WAIT_FAILED) then
    begin
      {$IFDEF _ICOP_DEBUGERR}
      _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_WSA_WAIT_FAILED', []);
      {$ENDIF}
      Break;
    end;
    nIndex := nIndex - WAIT_OBJECT_0;
    (* 停止服务内核对象         *)
    if (nIndex = 0) then
      begin
        {$IFDEF _ICOP_DEBUGCLOSE}
        _GlobalLogger.AppendLogMessage('IOCP_ERROR_LISTNERTHREAD_GET_SHUTDOWNEVENT', []);
        {$ENDIF}
        Break;
      end  (* m_hPostAcceptEvent事件，I/O的线程连接新用户，投递维持一定AcceptEx数量 *)
    else if (nIndex = 1) then
      m_nPostAccepts := InterlockedExchange(m_iIOCPPostAccepts, 0)
    else
      begin
        if (nIndex = 2) then
        begin
         nRet := WinSock2Ex.WSAEnumNetworkEvents(m_sListenSocket, m_hWaitEventList[nIndex], Events);
         if (nRet = SOCKET_ERROR) then
         begin
           {$IFDEF _ICOP_DEBUGERR}
           _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_WSAENUMEVENT_EXCEPT', [WSAGetLastError()]);
           {$ENDIF}
           Break;
         end;
         if (Events.lNetworkEvents = FD_ACCEPT) then
         begin
           (* 多次检查m_bEngineShutDown状态，以便退出线程 *)
           if (Events.iErrorCode[FD_ACCEPT_BIT] = 0 ) then
             m_nPostAccepts := 50
           else
             begin
               {$IFDEF _ICOP_DEBUGERR}
               _GlobalLogger.AppendErrorLogMessage('IOCP_ERROR_LISTNERTHREAD_WSAENUMEVENT_EXCEPT', [WSAGetLastError()]);
               {$ENDIF}
               Break;
             end;
         end;
        end;
      end;
    (* 继续投递一定数量的AcceptEx I/O  *)
    m_nPostAccepts := PostAcceptIOCount;
    {$IFDEF _ICOP_DEBUGCLOSE}
    if m_nPostAccepts > 1 then
      _GlobalLogger.AppendErrorLogMessage('ListnerThreadProc:%d', [m_nPostAccepts]);
    {$ENDIF}
    InitPostAcceptEx(m_nPostAccepts);
  end;
  {$IFDEF _ICOP_DEBUGCLOSE}
  _GlobalLogger.AppendErrorLogMessage('IOCP_LISTNERTHREAD_EXIT', []);
  {$ENDIF}
end;

procedure TITCPListener.StopListener;
var
  i: Integer;
  FMapBuffer: TIMapBuffer;
  FSocket: THandle;
begin
  if not m_bStarted then Exit;
  (* 关闭所有套接字             *)
  CloseAllClientContext;
  (* 关闭AccpetEx套接字         *)
  FMapBuffer := m_DIEngine.MemoryPool.MapAcceptBuffer;
  with FMapBuffer do
  begin
    MapBufferLock.Lock;
    try
      for i := 0 to Buckets.Count - 1 do begin
        if ((PTIBufferNode(Buckets[i])^.IsUsed) and
             (PTIBufferNode(Buckets[i])^.Buffer <> nil)) then
        begin
          FSocket := PTIBufferNode(Buckets[i])^.Buffer.FSocket;
          if FSocket <> INVALID_SOCKET then
            CloseWinSocket(FSocket);
        end;
      end;
    finally
      MapBufferLock.UnLock;
    end;
  end;
  (* 停止侦听线程               *)
  SetEvent(m_hShutdownEvent);
  Sleep(10);
  WaitForSingleObject(m_hListnerEngineThread.Handle, INFINITE);
  FreeAndNil(m_hListnerEngineThread);
  CloseHandle(m_hShutdownEvent);
  m_hShutdownEvent := INVALID_HANDLE_VALUE;
  CloseHandle(m_hListnerThreadEvent);
  m_hListnerThreadEvent := INVALID_HANDLE_VALUE;
  CloseHandle(m_hPostAcceptEvent);
  m_hPostAcceptEvent := INVALID_HANDLE_VALUE;
  (* 关闭侦听套接字             *)
  WinSock2Ex.shutdown(m_sListenSocket, SD_BOTH);
  CloseWinSocket(m_sListenSocket);
  m_sListenSocket := INVALID_SOCKET;
  m_bStarted := False;
end;

end.
